package gbasebak

import (
	"bytes"
	"context"
	"crypto/tls"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"testing"
	"time"

	"github.com/cloudwego/hertz/pkg/common/hlog"
)

const (
	// 内容类型常量
	ContentTypeJSON      = "application/json"
	ContentTypeForm      = "application/x-www-form-urlencoded"
	ContentTypeMultipart = "multipart/form-data"
	ContentTypeXML       = "application/xml"
	ContentTypeText      = "text/plain"

	// 默认超时时间（秒）
	DefaultTimeout = 60

	// HTTP方法
	MethodGet     = "GET"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodDelete  = "DELETE"
	MethodPatch   = "PATCH"
	MethodHead    = "HEAD"
	MethodOptions = "OPTIONS"
)

// HttpClient 是基于标准库的HTTP客户端
type HttpClient struct {
	client      *http.Client
	transport   *http.Transport
	headers     Map
	cookies     []*http.Cookie
	url         string
	method      string
	queryParams url.Values
	formData    url.Values
	multipart   *multipart.Writer
	body        io.Reader
	bodyBuf     *bytes.Buffer
	contentType string
	timeout     time.Duration
	ctx         context.Context
	retryCount  int
	retryWait   time.Duration
	mutex       sync.RWMutex
	debug       bool
}

// HttpResponse 是HTTP响应的封装
type HttpResponse struct {
	StatusCode int
	Status     string
	Headers    http.Header
	Cookies    []*http.Cookie
	Body       []byte
	Request    *http.Request
	Response   *http.Response
	Error      error
}

// NewHttpClient 创建一个新的HTTP客户端
func NewHttpClient() *HttpClient {
	transport := &http.Transport{
		MaxIdleConns:        100,
		MaxIdleConnsPerHost: 10,
		IdleConnTimeout:     30 * time.Second,
		// 增加以下配置以提高连接稳定性
		DisableKeepAlives:     false,
		TLSHandshakeTimeout:   10 * time.Second,
		ExpectContinueTimeout: 1 * time.Second,
		ResponseHeaderTimeout: 10 * time.Second,
		// 默认不使用代理
		Proxy: nil,
	}

	return &HttpClient{
		client: &http.Client{
			Transport: transport,
			Timeout:   time.Duration(DefaultTimeout) * time.Second,
		},
		transport:   transport,
		headers:     Map{},
		queryParams: url.Values{},
		formData:    url.Values{},
		bodyBuf:     &bytes.Buffer{},
		timeout:     time.Duration(DefaultTimeout) * time.Second,
		ctx:         context.Background(),
		retryCount:  0,
		retryWait:   time.Second,
	}
}

// WithContext 设置上下文
func (h *HttpClient) WithContext(ctx context.Context) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.ctx = ctx
	return h
}

// WithTimeout 设置超时时间
func (h *HttpClient) WithTimeout(timeout int) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.timeout = time.Duration(timeout) * time.Second
	h.client.Timeout = h.timeout
	return h
}

// WithRetry 设置重试次数和等待时间
func (h *HttpClient) WithRetry(count int, wait time.Duration) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.retryCount = count
	h.retryWait = wait
	return h
}

// WithHeader 设置单个请求头
func (h *HttpClient) WithHeader(key, value string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.headers[key] = value
	return h
}

// WithHeaders 设置多个请求头
func (h *HttpClient) WithHeaders(headers Map) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	for k := range headers {
		h.headers[k] = headers.GetString(k)
	}
	return h
}

// WithCookie 设置Cookie
func (h *HttpClient) WithCookie(cookie *http.Cookie) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.cookies = append(h.cookies, cookie)
	return h
}

// WithContentType 设置内容类型
func (h *HttpClient) WithContentType(contentType string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.contentType = contentType
	h.headers["Content-Type"] = contentType
	return h
}

// WithJSON 设置JSON内容类型和Accept头
func (h *HttpClient) WithJSON() *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.contentType = ContentTypeJSON
	h.headers["Content-Type"] = ContentTypeJSON
	h.headers["Accept"] = "application/json, text/javascript, */*; q=0.01"
	return h
}

// WithForm 设置表单内容类型
func (h *HttpClient) WithForm() *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.contentType = ContentTypeForm
	h.headers["Content-Type"] = ContentTypeForm
	h.headers["Accept"] = "application/json, text/javascript, */*; q=0.01"
	return h
}

// WithMultipart 设置多部分表单内容类型
func (h *HttpClient) WithMultipart() *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.bodyBuf = &bytes.Buffer{}
	h.multipart = multipart.NewWriter(h.bodyBuf)
	h.contentType = h.multipart.FormDataContentType()
	h.headers["Content-Type"] = h.contentType
	h.headers["Accept"] = "application/json, text/javascript, */*; q=0.01"
	return h
}

// WithXML 设置XML内容类型
func (h *HttpClient) WithXML() *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.contentType = ContentTypeXML
	h.headers["Content-Type"] = ContentTypeXML
	h.headers["Accept"] = "application/json, text/javascript, */*; q=0.01"
	return h
}

// WithURL 设置URL
func (h *HttpClient) WithURL(url string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.url = url
	return h
}

// WithMethod 设置HTTP方法
func (h *HttpClient) WithMethod(method string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.method = strings.ToUpper(method)
	return h
}

// WithQuery 添加查询参数
func (h *HttpClient) WithQuery(key, value string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.queryParams.Add(key, value)
	return h
}

// WithQueryMap 添加多个查询参数
func (h *HttpClient) WithQueryMap(params Map) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	for k := range params {
		h.queryParams.Add(k, params.GetString(k))
	}
	return h
}

// WithFormData 添加表单数据
func (h *HttpClient) WithFormData(key, value string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.formData.Add(key, value)
	return h
}

// WithFormDataMap 添加多个表单数据
func (h *HttpClient) WithFormDataMap(data Map) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	for k := range data {
		h.formData.Add(k, data.GetString(k))
	}
	return h
}

// WithFile 添加文件到多部分表单
func (h *HttpClient) WithFile(fieldName, filePath string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	if h.multipart == nil {
		h.WithMultipart()
	}

	file, err := os.Open(filePath)
	if err != nil {
		hlog.Errorf("打开文件失败: %s", err.Error())
		return h
	}
	defer file.Close()

	part, err := h.multipart.CreateFormFile(fieldName, filepath.Base(filePath))
	if err != nil {
		hlog.Errorf("创建表单文件失败: %s", err.Error())
		return h
	}

	_, err = io.Copy(part, file)
	if err != nil {
		hlog.Errorf("复制文件内容失败: %s", err.Error())
	}

	return h
}

// WithMultipartField 添加字段到多部分表单
func (h *HttpClient) WithMultipartField(fieldName, value string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	if h.multipart == nil {
		h.WithMultipart()
	}

	_ = h.multipart.WriteField(fieldName, value)
	return h
}

// WithBody 设置请求体
func (h *HttpClient) WithBody(body string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.body = strings.NewReader(body)
	return h
}

// WithJSONBody 设置JSON请求体
func (h *HttpClient) WithJSONBody(data interface{}) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	h.WithJSON()
	jsonData, err := json.Marshal(data)
	if err != nil {
		hlog.Errorf("JSON编码失败: %s", err.Error())
		return h
	}

	h.body = bytes.NewReader(jsonData)
	return h
}

// WithDebug 启用调试模式
func (h *HttpClient) WithDebug(debug bool) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()
	h.debug = debug
	return h
}

// buildURL 构建完整URL
func (h *HttpClient) buildURL() string {
	if len(h.queryParams) == 0 {
		return h.url
	}

	if strings.Contains(h.url, "?") {
		return h.url + "&" + h.queryParams.Encode()
	}
	return h.url + "?" + h.queryParams.Encode()
}

// prepareRequest 准备HTTP请求
func (h *HttpClient) prepareRequest() (*http.Request, error) {
	var reqBody io.Reader

	// 处理请求体
	if h.body != nil {
		reqBody = h.body
	} else if h.multipart != nil {
		h.multipart.Close()
		reqBody = h.bodyBuf
	} else if len(h.formData) > 0 && (h.method == MethodPost || h.method == MethodPut || h.method == MethodPatch) {
		if h.contentType == ContentTypeJSON {
			data := make(map[string]string)
			for k := range h.formData {
				data[k] = h.formData.Get(k)
			}
			jsonData, err := json.Marshal(data)
			if err != nil {
				return nil, err
			}
			reqBody = bytes.NewReader(jsonData)
		} else {
			reqBody = strings.NewReader(h.formData.Encode())
		}
	}

	// 创建请求
	req, err := http.NewRequestWithContext(h.ctx, h.method, h.buildURL(), reqBody)
	if err != nil {
		return nil, err
	}

	// 设置请求头
	for k := range h.headers {
		req.Header.Set(k, h.headers.GetString(k))
	}

	// 设置Cookie
	for _, cookie := range h.cookies {
		req.AddCookie(cookie)
	}

	return req, nil
}

// WithProxy 设置HTTP代理
func (h *HttpClient) WithProxy(proxyURL string) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	if proxyURL == "" {
		h.transport.Proxy = nil
	} else {
		proxy, err := url.Parse(proxyURL)
		if err == nil {
			h.transport.Proxy = http.ProxyURL(proxy)
		} else {
			hlog.Errorf("代理URL解析失败: %s", err.Error())
		}
	}

	// 更新client的transport
	h.client.Transport = h.transport
	return h
}

// WithTLSConfig 设置TLS配置
func (h *HttpClient) WithTLSConfig(skipVerify bool) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	if h.transport.TLSClientConfig == nil {
		h.transport.TLSClientConfig = &tls.Config{
			InsecureSkipVerify: skipVerify,
		}
	} else {
		h.transport.TLSClientConfig.InsecureSkipVerify = skipVerify
	}

	// 更新client的transport
	h.client.Transport = h.transport
	return h
}

// WithKeepAlives 设置是否保持连接
func (h *HttpClient) WithKeepAlives(enable bool) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	h.transport.DisableKeepAlives = !enable

	// 更新client的transport
	h.client.Transport = h.transport
	return h
}

// WithConnectTimeout 设置连接超时时间
func (h *HttpClient) WithConnectTimeout(timeout time.Duration) *HttpClient {
	h.mutex.Lock()
	defer h.mutex.Unlock()

	h.transport.DialContext = (&net.Dialer{
		Timeout:   timeout,
		KeepAlive: 30 * time.Second,
	}).DialContext

	// 更新client的transport
	h.client.Transport = h.transport
	return h
}

// WithUserAgent 设置User-Agent
func (h *HttpClient) WithUserAgent(userAgent string) *HttpClient {
	return h.WithHeader("User-Agent", userAgent)
}

// Do 执行HTTP请求
func (h *HttpClient) Do() *HttpResponse {
	if h.method == "" {
		h.method = MethodGet
	}

	req, err := h.prepareRequest()
	if err != nil {
		return &HttpResponse{Error: err}
	}

	if h.debug {
		hlog.Debugf("请求URL: %s", req.URL.String())
		hlog.Debugf("请求方法: %s", req.Method)
		hlog.Debugf("请求头: %v", req.Header)
		if h.transport.Proxy != nil {
			hlog.Debugf("使用代理")
		}
	}

	var resp *http.Response
	var respErr error

	// 重试逻辑
	for i := 0; i <= h.retryCount; i++ {
		if i > 0 {
			hlog.Debugf("重试请求 #%d", i)
			time.Sleep(h.retryWait)
		}

		resp, respErr = h.client.Do(req)
		if respErr == nil {
			break
		} else if h.debug {
			hlog.Errorf("请求失败: %s", respErr.Error())
		}
	}

	if respErr != nil {
		return &HttpResponse{Error: respErr}
	}

	defer resp.Body.Close()

	// 读取响应体
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return &HttpResponse{
			StatusCode: resp.StatusCode,
			Status:     resp.Status,
			Headers:    resp.Header,
			Cookies:    resp.Cookies(),
			Request:    req,
			Response:   resp,
			Error:      err,
		}
	}

	if h.debug {
		hlog.Debugf("响应状态: %s", resp.Status)
		hlog.Debugf("响应头: %v", resp.Header)
		hlog.Debugf("响应体长度: %d bytes", len(body))
		if len(body) < 1024 {
			hlog.Debugf("响应体: %s", string(body))
		}
	}

	return &HttpResponse{
		StatusCode: resp.StatusCode,
		Status:     resp.Status,
		Headers:    resp.Header,
		Cookies:    resp.Cookies(),
		Body:       body,
		Request:    req,
		Response:   resp,
	}
}

// Get 发送GET请求
func (h *HttpClient) Get(url string, params ...Map) *HttpResponse {
	h.WithMethod(MethodGet).WithURL(url)
	if len(params) > 0 {
		h.WithQueryMap(params[0])
	}
	return h.Do()
}

// Post 发送POST请求
func (h *HttpClient) Post(url string, data ...Map) *HttpResponse {
	h.WithMethod(MethodPost).WithURL(url)
	if len(data) > 0 {
		if h.contentType == ContentTypeJSON {
			h.WithJSONBody(data[0])
		} else {
			h.WithFormDataMap(data[0])
		}
	}
	return h.Do()
}

// Put 发送PUT请求
func (h *HttpClient) Put(url string, data ...Map) *HttpResponse {
	h.WithMethod(MethodPut).WithURL(url)
	if len(data) > 0 {
		if h.contentType == ContentTypeJSON {
			h.WithJSONBody(data[0])
		} else {
			h.WithFormDataMap(data[0])
		}
	}
	return h.Do()
}

// Delete 发送DELETE请求
func (h *HttpClient) Delete(url string, params ...Map) *HttpResponse {
	h.WithMethod(MethodDelete).WithURL(url)
	if len(params) > 0 {
		h.WithQueryMap(params[0])
	}
	return h.Do()
}

// Patch 发送PATCH请求
func (h *HttpClient) Patch(url string, data ...Map) *HttpResponse {
	h.WithMethod(MethodPatch).WithURL(url)
	if len(data) > 0 {
		if h.contentType == ContentTypeJSON {
			h.WithJSONBody(data[0])
		} else {
			h.WithFormDataMap(data[0])
		}
	}
	return h.Do()
}

// Head 发送HEAD请求
func (h *HttpClient) Head(url string) *HttpResponse {
	return h.WithMethod(MethodHead).WithURL(url).Do()
}

// Options 发送OPTIONS请求
func (h *HttpClient) Options(url string) *HttpResponse {
	return h.WithMethod(MethodOptions).WithURL(url).Do()
}

// PostFile 发送包含文件的POST请求
func (h *HttpClient) PostFile(url, fieldName, filePath string, data ...Map) *HttpResponse {
	h.WithMethod(MethodPost).WithURL(url).WithMultipart().WithFile(fieldName, filePath)
	if len(data) > 0 {
		for k := range data[0] {
			h.WithMultipartField(k, data[0].GetString(k))
		}
	}
	return h.Do()
}

// String 获取响应体字符串
func (r *HttpResponse) String() string {
	if r.Error != nil {
		return ""
	}
	return string(r.Body)
}

// JSON 将响应体解析为JSON
func (r *HttpResponse) JSON(v interface{}) error {
	if r.Error != nil {
		return r.Error
	}
	return json.Unmarshal(r.Body, v)
}

// IsSuccess 检查响应是否成功
func (r *HttpResponse) IsSuccess() bool {
	return r.Error == nil && r.StatusCode >= 200 && r.StatusCode < 300
}

// IsError 检查响应是否为错误
func (r *HttpResponse) IsError() bool {
	return r.Error != nil || r.StatusCode >= 400
}

// ToResp 转换为通用Resp对象
func (r *HttpResponse) ToResp() *Resp {
	if r.Error != nil {
		return NewFailResp(100, r.Error.Error())
	}

	if r.IsSuccess() {
		return NewSuccessResp(r.StatusCode, r.String(), "ok")
	}

	return NewFailResp(r.StatusCode, r.String())
}

func TestXx(t *testing.T) {
	url := "https://api.binance.com/api/v1/exchangeInfo"
	method := "GET"

	client := &http.Client{}
	req, err := http.NewRequest(method, url, nil)

	if err != nil {
		fmt.Println(err)
		return
	}
	//req.Header.Add("User-Agent", "Apifox/1.0.0 (https://apifox.com)")
	//req.Header.Add("Accept", "*/*")
	//req.Header.Add("Host", "api.binance.com")
	//req.Header.Add("Connection", "keep-alive")

	res, err := client.Do(req)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer res.Body.Close()

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(string(body))
}
